"""
Database inteface between the GUI frontend and the SQL backend
Written By: Daniel Ortiz
Date: November 5 2007
Version: 0.0
"""
import processing, time
from broker import MailBroker, DatabaseCollision
from Queue import Empty
import mapclass
import inspect

class DatabaseProcess(processing.Process):
    """The process which contains the SQLAlchemy database"""
    def __init__(self, namespace, dq, ttq, aq, rq):
        processing.Process.__init__(self)
        self.setDaemon(True)

        # Broker
        self.broker = MailBroker('mail.db')

        # Namespace
        self.namespace = namespace

        # Events
        self.DatabaseQuery = dq
        self.TimeToQuit = ttq

        # Queues
        self.ArgQueue = aq
        self.ResultQueue = rq

    def block(self):
        """Reset events in the process and block until next command received"""
        self.TimeToQuit.clear()

        # Blocking wait
        self.DatabaseQuery.clear()
        self.DatabaseQuery.wait()

    def run(self):
        """Running process"""
        while True:
            # Reset, and block until next call
            #self.block()
            try:
                while True:
                    t = self.ArgQueue.get(timeout = .0000001)
                    self.decode(t)
                    if self.TimeToQuit.isSet():
                        break
            except Empty:
                pass

            if self.TimeToQuit.isSet():
                self.broker.close()
                break

    def package_list(self, args):
        """Function packages a list across the db interface"""
        obj = []
        rl = len(args) / 2
        for v in range(rl):
            if args[2*v] == 'List':
                t = self.package_list(args[2 * v + 1])
                obj.append(t)
            else:
                t = getattr(mapclass, args[2 * v])
                d = [v for v in args[2 * v + 1]]
                obj.append(t(*d))
        return obj 
    
    def decode(self, arg):
        """Function decodes the argument from the Argument Queue and calls the
        appropriate MailBroker function"""
        func = arg[0]
        args = arg[1]
        children = False
        if len(arg) > 2:
            extra = arg[2:]
            for e in extra:
                if e == '--with-children':
                    children = True
        try:
            attr = getattr(self.broker, func)
            try:
                if args:
                    try:
                        obj = self.package_list(args)
                        result = attr(*obj)
                    except AttributeError:
                        result = AttributeError
                    except DatabaseCollision:
                        result = DatabaseCollision
                else:
                    result = attr()
            except TypeError:
                result = TypeError
        except AttributeError:
            result = AttributeError
        if not result in [AttributeError, TypeError, DatabaseCollision]:
            if isinstance(result, bool):
                self.ResultQueue.put([func, result])
            else:
                if result:
                    if children:
                        tqueue = []
                        for v in result:
                            for t in inspect.getmembers(v):
                                if t[0] == '__dict__':
                                    members = t[1]
                            cand = [val for key, val in members.iteritems() if isinstance(val, list) and val]
                            attr = getattr(mapclass, v.oname())
                            tqueue.append(attr(*v.get()))

                            # Iterates over the current class scope of an SQLAlchemy mapper and extracts
                            # the information into the current process context.
                            children = []
                            for c in cand:
                                for v in c:
                                    attr = getattr(mapclass, v.oname())
                                    children.append(attr(*v.get()))
                            if children:
                                tqueue.append(children)
                        vresult = [func, tqueue]
                    else:
                        tqueue = []
                        for v in result:
                            attr = getattr(mapclass, v.oname())
                            tqueue.append(attr(*v.get()))
                        vresult = [func, tqueue]
                    self.ResultQueue.put(vresult)
                else:
                    self.ResultQueue.put([func, True])
        else:
            self.ResultQueue.put([func, result])

if __name__ == '__main__':
    from mapclass import Owner, User

    # Namespace and Manager
    manager = processing.Manager()
    namespace = manager.Namespace()

    # Events
    DatabaseQuery = manager.Event()
    TimeToQuit = manager.Event()

    # Argument/Result Queues
    ArgQueue = manager.Queue()
    ArgQueue.put(['GetMail', [], '--with-children'])
    ResultQueue = manager.Queue()

    # Process
    process = DatabaseProcess(namespace, DatabaseQuery, TimeToQuit, ArgQueue, ResultQueue)
    process.start()
    o = ResultQueue.get()
    print o
    TimeToQuit.set()
    process.join()
    
            
